#include "qdes.h"
#include <QDebug>

static const uint8_t k1[] = DES_KEY1;
static const uint8_t k2[] = DES_KEY2;
static const uint8_t k3[] = DES_KEY3;

QDes::QDes(QObject *parent)
    : QObject(parent)
    , des(*(uint64_t *)k1)
    , des3(*(uint64_t *)k1, *(uint64_t *)k2, *(uint64_t *)k3)
{

}

void QDes::encrypt(QByteArray &bytes)
{
    uint32_t size = bytes.size();
    char * in = bytes.data();

    uint32_t block = size / 8;
    uint32_t i;
    uint64_t buffer;

    for (i = 0; i < block; i++)
    {
        memcpy(&buffer, &in[i*8], 8);
        buffer = des.encrypt(buffer);
        memcpy(&in[i*8], &buffer, 8);
    }

    // Amount of padding needed
    uint8_t padding = 8 - (size % 8);

    // Padding cannot be 0 (pad full block)
    if (padding == 0)
        padding  = 8;

    // Read remaining part of bytes
    buffer = (uint64_t) 0;
    if(padding != 8)
        memcpy(&buffer, &in[i*8], 8 - padding);

    // Pad block with a 1 followed by 0s
    uint8_t shift = padding * 8;
    buffer <<= shift;
    buffer  |= (uint64_t) 0x0000000000000001 << (shift - 1);

    buffer = des.encrypt(buffer);
    bytes.resize(i*8);
    bytes.append((char *)&buffer, 8);
}

void QDes::decrypt(QByteArray &bytes)
{
    uint32_t size = bytes.size();
    char * in = bytes.data();

    uint32_t block = size / 8;
    uint32_t i;
    uint64_t buffer;

    if (block > 0) { block--; }

    for (i = 0; i < block; i++)
    {
        memcpy(&buffer, &in[i*8], 8);
        buffer = des.decrypt(buffer);
        memcpy(&in[i*8], &buffer, 8);
    }

    // Read last block of bytes
    memcpy(&buffer, &in[i*8], 8);
    buffer = des.decrypt(buffer);

    // Amount of padding on bytes
    uint8_t padding = 0;

    // Check for and record padding on end
    while(!(buffer & 0x00000000000000ff))
    {
        buffer >>= 8;
        padding++;
    }

    buffer >>= 8;
    padding++;

    bytes.resize(i*8);

    if(padding != 8)
        bytes.append((char *)&buffer, 8 - padding);
}

void QDes::encrypt3(QByteArray &bytes)
{
    uint32_t size = bytes.size();
    char * in = bytes.data();

    uint32_t block = size / 8;
    uint32_t i;
    uint64_t buffer;

    for (i = 0; i < block; i++)
    {
        memcpy(&buffer, &in[i*8], 8);
        buffer = des3.encrypt(buffer);
        memcpy(&in[i*8], &buffer, 8);
    }

    // Amount of padding needed
    uint8_t padding = 8 - (size % 8);

    // Padding cannot be 0 (pad full block)
    if (padding == 0)
        padding  = 8;

    // Read remaining part of bytes
    buffer = (uint64_t) 0;
    if(padding != 8)
        memcpy(&buffer, &in[i*8], 8 - padding);

    // Pad block with a 1 followed by 0s
    uint8_t shift = padding * 8;
    buffer <<= shift;
    buffer  |= (uint64_t) 0x0000000000000001 << (shift - 1);

    buffer = des3.encrypt(buffer);
    bytes.resize(i*8);
    bytes.append((char *)&buffer, 8);

//    qDebug() << "加密" << bytes << tmp;
}

void QDes::decrypt3(QByteArray &bytes)
{
    uint32_t size = bytes.size();
    char * in = bytes.data();

    uint32_t block = size / 8;
    uint32_t i;
    uint64_t buffer;

    if (block > 0) { block--; }

    for (i = 0; i < block; i++)
    {
        memcpy(&buffer, &in[i*8], 8);
        buffer = des3.decrypt(buffer);
        memcpy(&in[i*8], &buffer, 8);
    }

    // Read last block of bytes
    memcpy(&buffer, &in[i*8], 8);
    buffer = des3.decrypt(buffer);

    // Amount of padding on bytes
    uint8_t padding = 0;

    // Check for and record padding on end
    while(!(buffer & 0x00000000000000ff))
    {
        buffer >>= 8;
        padding++;
    }

    buffer >>= 8;
    padding++;

    bytes.resize(i*8);

    if(padding != 8)
        bytes.append((char *)&buffer, 8 - padding);

//    qDebug() << "解密" << bytes << tmp;
}
